package com.wangshuqi.spring.aop;

import com.wangshuqi.spring.entity.User;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

@Component
@Aspect
public class UserAspect {


    @Pointcut(value = "execution(* com.wangshuqi.spring.service.impl.*.*(..))")
    public void pointcut() {
    }


    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("====before方法进入了====");
        // 获取签名
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();

        // 获取即将执行的方法名
        String funcName = signature.getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("即将执行方法为属于" + declaringTypeName + "包, 方法名：" + funcName + ",参数：" + Arrays.toString(args));
        Class declaringType = signature.getDeclaringType();
        System.out.println(declaringType.getTypeName());
        // 如果是web访问，也可以用来记录一些信息，比如获取请求的url和ip
        /*ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取请求url
        String url = request.getRequestURL().toString();
        // 获取请求ip
        String ip = request.getRemoteAddr();
        System.out.println("用户请求的url为：" + url + "，ip地址为：" + ip);*/
    }


    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("====around方法进入了====");
        System.out.println("around环绕之前。。。");
        Object proceed = joinPoint.proceed();// 被增强的方法执行
        System.out.println("around环绕之后。。。");
        return proceed;
    }


    @After("pointcut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("====after方法进入了====");
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 获取注解Transactional
//        Transactional transactional = method.getAnnotation(Transactional.class);
        method.setAccessible(true);
        Annotation[] annotations = method.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            String str = annotation.toString();
            System.out.println(str);
            if (str.contains("Transactional")) {
                Transactional transactional = method.getAnnotation(Transactional.class);
                Class<? extends Throwable>[] classes = transactional.rollbackFor();
                for (Class<? extends Throwable> aClass : classes) {
                    String typeName = aClass.getTypeName();
                    System.out.println("触发回滚的异常类是：" + typeName);
                }
            }
        }
    }

    /**
     * 方法执行返回后
     *
     * @author wangshuqi
     * @date 2024/4/22 17:17
     */
    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("====afterReturning方法进入了====");
        Signature signature = joinPoint.getSignature();
        String classMethod = signature.getName();
        System.out.println("方法" + classMethod + "执行完毕,执行结果返回数据：" + result);
        // 实际也可对结果进行修改
        if (result instanceof User){
            User user = (User) result;
            user.setName("张三");
        }
    }


    @AfterThrowing(value = "pointcut()", throwing = "exception")
    public void afterThrows(JoinPoint joinPoint, Exception exception) {
        System.out.println("====afterThrows方法进入了====");
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        // 获取即将执行的方法名
        String funcName = signature.getName();
        // 获取执行方法的参数列表
        Object[] args = joinPoint.getArgs();

        System.out.println("异常方法：" + declaringTypeName + funcName + ",\n异常参数：" + Arrays.toString(args)
                + ",\n异常信息：" + exception);
    }

}
